import Enumerable = require("linq");
import { Transaction } from "tiny-entity2";
import { IQueryObject } from "tiny-entity2/queryObject";
import { Guid } from "../common";
import { ServiceException } from "../common/excpetion";
import { ApiDataContext } from "../domain/apiDataContext";
import { OrganizationTree } from "../domain/models/organizationTree";
import { User } from "../domain/models/user";
import { Account } from "../domain/models/account";
import { BaseService, QueryParamsBase } from "./baseService";

export class UserService extends BaseService {
    GetUserByAccountId(id: string) {
        let ctx = new ApiDataContext();
        return ctx.User.First(x => x.accountId == $args1, { $args1: id });
    }
    GetUserByPhone(phone: string, orgId: string) {
        let ctx = new ApiDataContext();
        return ctx.User.First(x => x.phone == $args1 && x.organizationId == $args2, { $args1: phone, $args2: orgId });
    }
    async CreateUser(entity: User, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        let has = await ctx.User.Any(x => x.employeeNo == $args1,
            {
                $args1: entity.employeeNo
            });

        if (has) {
            throw new ServiceException(`已经存在工号为【${entity.employeeNo}】的用户！`);
        }

        has = await ctx.User.Any(x => x.phone == $args1 && x.organizationId == $args2, { $args1: entity.phone, $args2: entity.organizationId });
        if (has) {
            throw new ServiceException(`已经存在手机号为【${entity.phone}】的用户！`);
        }

        entity.createTime = Date.now();
        entity.id = Guid.GetGuid();
        entity.isDelete = false;
        return Transaction(ctx, async (ctx) => {

            let d = new User();
            d.ConverToEntity(entity);
            return ctx.Create(d);
        });
    }
    async UpdateUser(entity: User, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let d = new User();
            d.ConverToEntity(entity);
            let has = await ctx.User.Any(x => x.employeeNo == $args1 && x.id != $args2,
                {
                    $args1: entity.employeeNo,
                    $args2: entity.id
                });

            if (has) {
                throw new ServiceException(`已经存在工号为【${entity.employeeNo}】的用户！`);
            }

            has = await ctx.User.Any(x => x.phone == $args1 && x.id != $args2 && x.organizationId == $args3,
                {
                    $args1: entity.phone,
                    $args2: entity.id,
                    $args3: entity.organizationId
                });

            if (has) {
                throw new ServiceException(`已经存在手机号为【${entity.phone}】的用户！`);
            }
            return ctx.Update(d);
        });
    }
    async DeleteUserLogic(userId: string, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let user = await ctx.User.First(x => x.id == $args1, { $args1: userId });
            user.isDelete = true;
            return ctx.Update(user);
        });
    }

    async DeleteUser(entity: User, ctx?: ApiDataContext) {
        ctx || (ctx = new ApiDataContext());
        return Transaction(ctx, async (ctx) => {
            let d = new User();
            d.ConverToEntity(entity);
            return ctx.Delete(d);
        });
    }
    async GetUserById(id: string) {
        let ctx = new ApiDataContext();
        return ctx.User.First(x => x.id == $args1, { $args1: id });
    }
    async QueryUser(params: UserQueryParams) {
        let q = this.GetQueryUserCtx(params);
        let total = await q.Count();

        let q2 = this.GetQueryUserCtx(params);
        if (params.countOfPage && params.pageIndex) {
            q2 = q2.Take(params.countOfPage).Skip(params.pageIndex - 1) as any;
        }
        let list = await q2.OrderByDesc(x => x.createTime).ToList();

        let userParentNodeIds = list.map(x => x.orgTree.parentId);
        userParentNodeIds = Enumerable.from(userParentNodeIds).distinct().toArray();

        if (userParentNodeIds && userParentNodeIds.length) {
            let ctx = new ApiDataContext();
            let userDepartments = await ctx.OrganizationTree.Contains(x => x.id, userParentNodeIds).ToList();
            list.map(x => {
                if (x.orgTree.parentId) {
                    x.departmentNode = userDepartments.find(n => n.id == x.orgTree.parentId);
                }
            })
        }

        return {
            total,
            list
        };
    }

    private GetQueryUserCtx(params: UserQueryParams) {
        let ctx = new ApiDataContext();
        let q = ctx.User as IQueryObject<User>;
        q = q.Join(ctx.OrganizationTree).On((m, f) => m.id == f.objectId)
        q = q.Join(ctx.Account).On((m, f) => m.accountId == f.id);
        q = q.Where(x => x.isDelete == $args1, { $args1: false });
        if (params) {
            if (params.organizationId) {
                q = q.Where(x => x.organizationId == $args1, { $args1: params.organizationId });
            }
            if (params.name) {
                q = q.Where(x => x.name.indexOf($args1) || x.phone.indexOf($args2), { $args1: params.name, $args2: params.name });
            }
            if (params.employeeNo) {
                q = q.Where(x => x.employeeNo.indexOf($args1), { $args1: params.employeeNo });
            }
            if (params.phone) {
                q = q.Where(x => x.phone.indexOf($args1), { $args1: params.phone });
            }
            if (params.gender) {
                q = q.Where(x => x.gender == $args1, { $args1: params.gender });
            }
            if (params.beginTime) {
                q = q.Where(x => x.createTime >= $args1, { $args1: params.beginTime });
            }
            if (params.endTime) {
                q = q.Where(x => x.createTime <= $args1, { $args1: params.endTime });
            }
            if (params.accountIds && params.accountIds.length > 0) {
                q = q.Contains(x => x.accountId, params.accountIds) as IQueryObject<User>;
            }
            if (params.parentId) {
                q = q.Where<OrganizationTree>(x => x.parentId == $args1, { $args1: params.parentId }, ctx.OrganizationTree);
            }
            if (params.superPermit) {
                q = q.Where<Account>(x => x.superPermits != null, {}, ctx.Account);
            }
        }
        return q;
    }
}

export interface UserQueryParams extends QueryParamsBase {
    name?: string;
    organizationId?: string;
    gender?: string;
    beginTime?: number;
    endTime?: number;
    employeeNo?: string;
    phone?: string;
    accountIds?: string[];
    parentId?: string;
    superPermit?: boolean;
}